﻿//#define USENEWASSETBUNDLESYSTEM
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using System.IO;
using System.Xml;
using GBFramework;


public class NewVersion {

    static List<FileSystemInfo> fileMessage = new List<FileSystemInfo>();

    /**
     * 
     *  版本号 为格式为 大版本号.小版本号
     *   
     *  小版本号为  x.x
     * 
     *  如 1.0.5
     * 
     *  C# 文件更新为大版本更新，
     *  
     *  资源更新为 小版本更新
     *  
     */
    public static string getVersionNum() {

        string streamPath = Application.streamingAssetsPath;

        byte[] ret = File.ReadAllBytes(streamPath + "/version.txt" );

        if (ret == null || ret.Length == 0)
            return "1.0.0";

        string versionNum = System.Text.Encoding.Default.GetString(ret);

        return versionNum;
    }

    public static void createVersion(string versionNum) {

        string streamPath = Application.streamingAssetsPath;

        FileInfo fi = new FileInfo(streamPath + "/streamPath.txt");
        using (StreamWriter sw = fi.CreateText()) {
            getFilePath(streamPath, sw);
        }

        //更新版本号
        fi = new FileInfo(streamPath + "/version.txt");
        using (StreamWriter sw = fi.CreateText()) {
            sw.Write(versionNum);
        }
#if USENEWASSETBUNDLESYSTEM
        string vesionDataPath = streamPath + "/VersionData.xml";
        //读取xml 如果没有则创建 第一次进行版本生成的时候不会进行versionupdate
        if ( !File.Exists(vesionDataPath) ) {
            InitVesionData(vesionDataPath,versionNum,streamPath);
            fileMessage.Clear();
        }
        else {
            VersionUpdate(vesionDataPath , versionNum,streamPath);
            fileMessage.Clear();
        }

        //写日志  创建相应的版本库
        WriteLog(vesionDataPath,versionNum);
#endif
        AssetDatabase.Refresh();
        Debug.Log("新版本生成成功, versionNum = " + versionNum);
    }

    [MenuItem("Mytools/ResetVersion")]
    public static void reset() {

        VersionManager.Instance.curVersion = "0.0.0";

        File.WriteAllBytes(Application.streamingAssetsPath + "/version.txt" ,System.Text.Encoding.UTF8.GetBytes(VersionManager.Instance.curVersion.ToString()));

        createMiniVersion();

    }

    [MenuItem("Mytools/NewMainVersion")]
    public static void createMainVersion(){

        string streamPath = Application.streamingAssetsPath;

        string curVersionNum = getVersionNum();

        Version v = new Version(curVersionNum);

        v.mainVersion++;

        createVersion(v.ToString());
    }

    [MenuItem("Mytools/NewMiniVersion")]
    public static void createMiniVersion() {
        
        string streamPath = Application.streamingAssetsPath;

        string curVersionNum = getVersionNum();

        Version v = new Version(curVersionNum);

        v.miniVersion ++;
 
        createVersion(v.ToString());
    }

    public static void getFilePath(string sourcePath , StreamWriter sw) {
        
        DirectoryInfo info = new DirectoryInfo(sourcePath);
        
        foreach ( FileSystemInfo fsi in info.GetFileSystemInfos() ) {
            
            if ( fsi.Extension != ".meta" && fsi.Name != "streamPath.txt" ) {
                
                string[] r = fsi.FullName.Split(new string[] { "StreamingAssets" } , System.StringSplitOptions.None); //得到相对路径
                
                r[ 1 ] = r[ 1 ].Replace('\\' , '/'); //安卓上只能识别"/"
                
                if ( fsi is DirectoryInfo ) { //是文件夹则迭代

                    sw.WriteLine(r[1] + " | 0"); //按行写入
					if(!fsi.FullName.EndsWith("AssetBundles")){
						getFilePath(fsi.FullName , sw);
					}

                } else {
                    
                    sw.WriteLine(r[1] + " | 1" + "|" + string.Format("{0:F}",((FileInfo)fsi).Length/1024.0f)); //按行写入
                    
                }
            }
        }
    }

    /// <summary>
    /// 获取路径下所有的文件 包括文件夹 并存放在 fileMessage 中
    /// </summary>
    /// <param name="sourcePat"></param>
    static void getFilePath(string sourcePat) {
        DirectoryInfo info = new DirectoryInfo(sourcePat);
        foreach ( FileSystemInfo fsi in info.GetFileSystemInfos() ) {
            if ( fsi.Extension != ".meta" ) {
                fileMessage.Add(fsi);
                if ( fsi is DirectoryInfo ) {
                    getFilePath(fsi.FullName);
                }
            }
        }
    }

    //将filesystemInfo 转换到filedata
    static void TransitionFileSystemInfo2FileData(FileSystemInfo fileinfo , out FileData filedata , FileStatus fileStatus) {
        filedata = new FileData();

        filedata.fileName = fileinfo.Name;
        string[] r = fileinfo.FullName.Split(new string[] { "StreamingAssets" } , System.StringSplitOptions.None); //得到相对路径
        r[ 1 ] = r[ 1 ].Replace('\\' , '/');
        filedata.filePath = r[ 1 ];
        filedata.fileStatus = ( ( int )fileStatus ).ToString();
        filedata.fileChangeTime = fileinfo.LastWriteTime.ToString("yyyyMMddHHmmss");
        if ( File.Exists(fileinfo.FullName) ) {
            filedata.fileType = ( ( int )FileType.file ).ToString();
        }
        else if ( Directory.Exists(fileinfo.FullName) ) {
            filedata.fileType = ( ( int )FileType.floder ).ToString();
        }
        else {
            filedata = null;
        }
    }

    /// <summary>
    /// 第一次进行备份文件数据
    /// </summary>
    /// <param name="xmlPath"></param>
    static void InitVesionData(string xmlPath , string version , string streamPath) {
        XmlDocument xml = new XmlDocument();
        XmlDeclaration xmldecl =   xml.CreateXmlDeclaration("1.0" , "gb2312" , null);
        xml.AppendChild(xmldecl);
        XmlElement ele = xml.CreateElement("" , "VersionDataRoot" , "");
        ele.SetAttribute("Version" , version);
        xml.AppendChild(ele);
        xml.Save(xmlPath);

        getFilePath(streamPath);

        //解析文件list 并保存在版本文件夹中
        foreach ( FileSystemInfo fsi in fileMessage ) {
            FileData filedata = null;
            TransitionFileSystemInfo2FileData(fsi , out filedata , FileStatus.add);
            if ( filedata == null )
                continue;
            XmlElement dataele = xml.CreateElement("FileDate");
            WriteFileDataToXmlNode(filedata , ref  dataele);
            ele.AppendChild(dataele);
        }
        xml.Save(xmlPath);


    }

    /// <summary>
    /// 版本更新
    /// </summary>
    static void VersionUpdate(string xmlPath , string version , string streamPath) {
        Debug.Log(" 已存在版本 对版本进行更新");
        //通过xml文件进行比对 是否存在以及时间是否正确
        //第一次备份后的后续进行版本更新时 状态一般是over 所以只用进行判断即可

        //获取全部的文件信息
        //fileMessage;
        Dictionary<string,FileData> nowFileinfo = new Dictionary<string , FileData>();
        Dictionary<string,FileData> lastFileinfo = new Dictionary<string , FileData>();

        XmlDocument xml = new XmlDocument();
        xml.Load(xmlPath);
        //获取xml内容信息     此处如果使用文件和文件夹的名称会出现同名 则换成路径来进行对比
        XmlNode node = xml.SelectSingleNode("VersionDataRoot");
        XmlNodeList xnl = node.ChildNodes;
        foreach ( XmlElement xnlchild in xnl ) {
            FileData data = new FileData();
            WriteXmlNodeToTileData(xnlchild , ref data);
            lastFileinfo.Add(data.filePath , data);
        }
        File.Delete(xmlPath);
        //删掉原来的 重写一个

        XmlDocument xmlDoc = new XmlDocument();
        XmlDeclaration xmldecl =   xmlDoc.CreateXmlDeclaration("1.0" , "gb2312" , null);
        xmlDoc.AppendChild(xmldecl);
        XmlElement ele = xmlDoc.CreateElement("" , "VersionDataRoot" , "");
        ele.SetAttribute("Version" , version);
        xmlDoc.AppendChild(ele);
        xmlDoc.Save(xmlPath);
        getFilePath(streamPath);

        foreach ( FileSystemInfo fsi in fileMessage ) {
            FileData filedata =null;
            string[] r = fsi.FullName.Split(new string[] { "StreamingAssets" } , System.StringSplitOptions.None); //得到相对路径
            r[ 1 ] = r[ 1 ].Replace('\\' , '/');
            string fsiPath = r[ 1 ];
            //如果当前的最新的文件 存在上次文件的列表中 则对比它们的修改时间来判断是否修改
            if ( lastFileinfo.ContainsKey(fsiPath) ) {
                //对比时间 获取上一次的文件信息
                filedata = lastFileinfo[ fsiPath ];
                //上一次的时间
                string fsitime =fsi.LastWriteTime.ToString("yyyyMMddHHmmss");
                //当前的时间和上一次对比
                if ( long.Parse(fsitime) > long.Parse(filedata.fileChangeTime) ) {
                    TransitionFileSystemInfo2FileData(fsi , out filedata , FileStatus.chang);
                }
                else if ( long.Parse(fsitime) < long.Parse(filedata.fileChangeTime) ) {
                    Debug.LogError("文件更新出错，上一次的更新时间大于最新的更新事件");
                }
                else {
                    //时间未发生变化 证明当前文件读写未发生变化
                    TransitionFileSystemInfo2FileData(fsi , out filedata , FileStatus.over);
                }
            }
            else {
                //本次更新的东西 不存在上一个版本中，则添加
                TransitionFileSystemInfo2FileData(fsi , out filedata , FileStatus.add);
            }
            
            if ( filedata != null ) {
                nowFileinfo.Add(filedata.filePath , filedata);
            }
        }

        foreach ( KeyValuePair<string,FileData> lastdata in lastFileinfo ) {
            //上个版本有的当前版本没有 则写入删除
            if ( !nowFileinfo.ContainsKey(lastdata.Key) ) {
                lastdata.Value.fileStatus = ( ( int )FileStatus.delete ).ToString();
                nowFileinfo.Add(lastdata.Key , lastdata.Value);
            }
        }

        foreach ( KeyValuePair<string,FileData> data in nowFileinfo ) {
            XmlElement fileEle = xmlDoc.CreateElement("FileDate");
            if ( int.Parse(data.Value.fileStatus) != ( int )FileStatus.over ) {
                WriteFileDataToXmlNode(data.Value , ref fileEle);
                ele.AppendChild(fileEle);
            }
        }
        xmlDoc.Save(xmlPath);
    }


    /// <summary>
    /// 写日志 并将需要修改的东西拷贝到一个版本文件夹中
    /// </summary>
    static void WriteLog(string xmlPath , string version) {
        //日志位置
        string logPath = Application.dataPath + "/VesionStore" + "/" + version;

        if ( !Directory.Exists(logPath) ) {
            Directory.CreateDirectory(logPath);
        }

        string streamingPath = Application.streamingAssetsPath;
        List<FileData> fileChangeList = new List<FileData>();

        XmlDocument xml = new XmlDocument();
        xml.Load(xmlPath);

        XmlNode node = xml.SelectSingleNode("VersionDataRoot");
        XmlNodeList xnl = node.ChildNodes;
        foreach ( XmlElement ele in xnl ) {
            FileData data = new FileData();
            //转换数据
            WriteXmlNodeToTileData(ele , ref data);
            //如果当前的data是 是文件是否增加修改进行拷贝
            //只处理添加的改过的和增加的
            //注此处的文件创建和文件夹的创建 是按照先创建文件夹 后拷贝文件来进行的操作
            //在遍历是总是先保存的文件夹后保存文件
            switch ( int.Parse(data.fileStatus) ) {
                case ( int )FileStatus.add:
                case ( int )FileStatus.chang: {
                        switch ( int.Parse(data.fileType) ) {
                            case ( int )FileType.file: {
                                    //case ( int )FileType.floder:
                                    //判断文件的上一级文件夹是否存在 不存在则创建
                                    string originalPath = streamingPath + data.filePath;
                                    string targetPath = logPath + data.filePath;
                                    string targetPathLastFloder = ResourceManager.GetFileOrFloderLastPath(targetPath);
                                    ResourceManager.CreateFolder(targetPathLastFloder);
                                    try {
                                        File.Copy(originalPath , targetPath , true);
                                    } catch ( System.Exception e ) {
                                        Debug.LogError(e.ToString());
                                    }
                                }
                                break;
                        }
                        //将更改过的文件写入日志
                        fileChangeList.Add(data);
                        break;
                    }
            }
        }

        string[] logContent = new string[ fileChangeList.Count + 1 ];
        logContent[ 0 ] = "版本为:" + version + "      修改过的文件如下";
        for ( int a =0 ; a < fileChangeList.Count ; a++ ) {
            logContent[ a + 1 ] = "文件名: " + fileChangeList[ a ].fileName + "   路径为: " + fileChangeList[ a ].filePath + "  修改时间为: " + fileChangeList[ a ].fileChangeTime + "    文件类型是: "
                + ( ( fileChangeList[ a ].fileType == ( ( int )FileType.file ).ToString() ) ? "文件" : "文件夹" ) + "   修改类型为: ";
            string filestatus = "error";
            switch ( int.Parse(fileChangeList[ a ].fileStatus) ) {
                case ( int )FileStatus.add:
                    filestatus = "  添加";
                    break;
                case ( int )FileStatus.delete:
                    filestatus = "  删除";
                    break;
                case ( int )FileStatus.chang:
                    filestatus = "  修改";
                    break;
                case ( int )FileStatus.over:
                    filestatus = "  未改";
                    break;
            }
            logContent[ a + 1 ] += filestatus;
        }
        File.WriteAllLines(logPath + "Log.txt" , logContent);
        Debug.Log("写出日志");
    }
       
    /// <summary>
    /// 将节点的信息写入到xmlelement
    /// </summary>
    /// <param name="filedata"></param>
    /// <param name="xml"></param>
    static void WriteFileDataToXmlNode(FileData filedata , ref XmlElement xml) {
        xml.SetAttribute(FileData.fileNameAttribute , filedata.fileName);
        xml.SetAttribute(FileData.filePathAttribute , filedata.filePath);
        xml.SetAttribute(FileData.fileChangeTimeAttribute , filedata.fileChangeTime);
        xml.SetAttribute(FileData.fileStatusAttribute , filedata.fileStatus);
        xml.SetAttribute(FileData.fileTypeAttribute , filedata.fileType);
    }
    /// <summary>
    /// 将xmlelement信息写入到节点中
    /// </summary>
    /// <param name="xml"></param>
    /// <param name="filedata"></param>
    static void WriteXmlNodeToTileData(XmlElement xml , ref FileData filedata) {
        filedata.fileName = xml.GetAttribute(FileData.fileNameAttribute);
        filedata.filePath = xml.GetAttribute(FileData.filePathAttribute);
        filedata.fileChangeTime = xml.GetAttribute(FileData.fileChangeTimeAttribute);
        filedata.fileStatus = xml.GetAttribute(FileData.fileStatusAttribute);
        filedata.fileType = xml.GetAttribute(FileData.fileTypeAttribute);
    }


}
